package cn.iocoder.yudao.module.system.service.autogeneration;

import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.controller.admin.examscore.vo.NewExamScoreImportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.examclass.ExamClassDO;
import cn.iocoder.yudao.module.system.dal.dataobject.examclass.ExamClassStudentDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.examclass.ExamClassMapper;
import cn.iocoder.yudao.module.system.dal.mysql.examclass.ExamClassStudentMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.util.PinyinUtils;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.util.StringUtils;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 自动生成 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class AutoGenerationServiceImpl implements AutoGenerationService {

    @Resource
    private ExamClassMapper examClassMapper;
    
    @Resource
    private ExamClassStudentMapper examClassStudentMapper;
    
    @Resource
    private AdminUserMapper adminUserMapper;
    
    @Resource
    private DeptMapper deptMapper;
    
    @Resource
    private PostMapper postMapper;
    
    @Resource
    private AdminUserService adminUserService;
    
    @Resource
    private PermissionService permissionService;
    
    @Resource
    private RoleService roleService;

    // 班级名称解析正则表达式
    private static final Pattern CLASS_NAME_PATTERN = Pattern.compile("(高[一二三]|初[一二三]|[1-9]年级)(\\(?([0-9]+)\\)?班)");
    
    // 默认密码
    private static final String DEFAULT_PASSWORD = "88888888";

    @Override
    @Transactional
    public Long autoCreateClass(String className, String grade, String description) {
        log.info("开始创建班级，班级名称: {}, 年级: {}, 描述: {}", className, grade, description);
        
        // 检查班级是否已存在
        ExamClassDO existingClass = checkClassExists(className);
        if (existingClass != null) {
            log.info("班级{}已存在，直接返回班级ID: {}", className, existingClass.getId());
            return existingClass.getId();
        }
        
        try {
            // 生成班级编码
            ClassInfo classInfo = parseClassInfo(className);
            log.debug("解析班级信息: 年级={}, 班级号={}, 描述={}", 
                     classInfo.getGrade(), classInfo.getClassNumber(), classInfo.getDescription());
            
            String classCode = generateClassCode(classInfo.getGrade(), classInfo.getClassNumber());
            log.debug("生成班级编码: {}", classCode);
            
            // 为新班级创建专门的班主任账号
            Long teacherId = createDefaultTeacher(className);
            log.info("为班级{}创建班主任账号，班主任ID: {}", className, teacherId);
            
            // 创建班级
            ExamClassDO examClass = new ExamClassDO();
            examClass.setClassName(className);
            examClass.setClassCode(classCode);
            examClass.setGrade(grade != null ? grade : classInfo.getGrade());
            examClass.setTeacherId(teacherId);
            examClass.setStudentCount(0);
            examClass.setDescription(description != null ? description : classInfo.getDescription());
            examClass.setStatus(1); // 启用状态
            
            // 设置当前登录用户的部门ID（用于数据权限控制）
            Long currentUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
            if (currentUserDeptId != null) {
                examClass.setDeptId(currentUserDeptId);
                log.debug("设置班级部门ID: {}, 班级: {}", currentUserDeptId, className);
            } else {
                log.warn("当前登录用户未设置部门ID，班级将不设置部门信息: {}", className);
            }
            
            examClassMapper.insert(examClass);
            log.info("成功创建班级: {}, 班级ID: {}, 班级编码: {}", className, examClass.getId(), classCode);
            
            return examClass.getId();
            
        } catch (Exception e) {
            log.error("创建班级失败，班级名称: {}, 错误: {}", className, e.getMessage(), e);
            throw new RuntimeException("创建班级失败: " + e.getMessage(), e);
        }
    }

    @Override
    public Long autoCreateClassFromName(String className) {
        ClassInfo classInfo = parseClassInfo(className);
        return autoCreateClass(className, classInfo.getGrade(), classInfo.getDescription());
    }

    @Override
    @Transactional
    public Long autoCreateStudent(NewExamScoreImportExcelVO studentData, Long classId) {
        studentData.setClassId(classId);
        ExamClassStudentDO existingStudent = checkStudentExists(studentData);
        if (existingStudent != null) {
            return existingStudent.getStudentId();
        }
        
        // 获取班级信息
        ExamClassDO examClass = examClassMapper.selectById(classId);
        if (examClass == null) {
            throw new RuntimeException("班级不存在：" + classId);
        }
        
        // 创建用户账号
        Long userId = autoCreateStudentUser(studentData, examClass.getClassCode());
        
        // 生成学号
        int currentStudentCount = examClassStudentMapper.countByClassId(classId);
        String studentNo = studentData.getStudentNo();
        if (studentNo == null || studentNo.isEmpty()) {
            studentNo = generateStudentNo(examClass.getClassCode(), currentStudentCount + 1);
        }
        
        // 创建学生记录
        ExamClassStudentDO student = new ExamClassStudentDO();
        student.setClassId(classId);
        student.setStudentId(userId);
        student.setStudentNo(studentNo);
        student.setStudentName(studentData.getStudentName());
        student.setClassName(studentData.getClassName()); // 设置班级名称
        student.setExamNo(studentData.getExamNo());
        student.setSubjectCombination(studentData.getSubjectCombination());
        student.setPhone(extractPhoneFromData(studentData));
        student.setEmail(extractEmailFromData(studentData));
        student.setJoinTime(LocalDateTime.now());
        student.setStatus(1); // 正常状态
        
        examClassStudentMapper.insert(student);
        
        // 更新班级学生数量
        examClass.setStudentCount(examClass.getStudentCount() + 1);
        examClassMapper.updateById(examClass);
        
        return userId;
    }

    @Override
    @Transactional
    public Long autoCreateStudentUser(NewExamScoreImportExcelVO studentData, String classCode) {
        try {
            log.debug("开始为学生{}创建用户账号", studentData.getStudentName());
            
            // 获取学生部门ID
            Long deptId = getStudentDeptId();
            if (deptId == null) {
                throw new RuntimeException("未找到学生部门，请先创建名为'学生部'的部门");
            }
            
            // 生成基础用户名（基于姓名、部门ID和班级代码）
            String baseUsername = generateStudentUsername(studentData.getStudentName(), classCode, deptId);
            log.debug("生成基础用户名: {}", baseUsername);
            
            // 首先检查基础用户名是否已存在
            // 这样可以确保同一个部门、同一个班级的同一个学生不会创建多个账号
            AdminUserDO existingUser = adminUserMapper.selectByUsername(baseUsername);
            if (existingUser != null) {
                log.info("学生用户{}已存在（同部门同班级同姓名），复用已有账号，用户ID: {}", baseUsername, existingUser.getId());
                return existingUser.getId();
            }
            
            // 如果基础用户名不存在，需要检查并确保其唯一性，避免并发冲突
            String username = generateUniqueUsername(baseUsername);
            log.debug("使用用户名: {}", username);
            
            // 获取学生岗位ID
            Long postId = getStudentPostId();
            if (postId == null) {
                throw new RuntimeException("未找到学生岗位，请先创建名为'学生'的岗位");
            }
            
            // 创建用户请求对象
            UserSaveReqVO createUserReq = new UserSaveReqVO();
            createUserReq.setUsername(username);
            createUserReq.setPassword(DEFAULT_PASSWORD); // 会自动加密
            createUserReq.setNickname(studentData.getStudentName());
            createUserReq.setRemark("系统自动创建的学生账号，初始密码：88888888，请首次登录后修改密码");
            createUserReq.setDeptId(deptId); // 学生部门
            createUserReq.setPostIds(Collections.singleton(postId)); // 学生岗位
            createUserReq.setEmail(extractEmailFromData(studentData));
            createUserReq.setMobile(extractPhoneFromData(studentData));
            createUserReq.setSex(0); // 未知性别
            createUserReq.setAvatar("");
            createUserReq.setStatus(1); // 启用状态
            
            // 使用AdminUserService创建用户，会自动加密密码
            Long userId = adminUserService.createUser(createUserReq);
            log.debug("成功创建学生用户，用户ID: {}", userId);
            
            // 自动分配学生角色
            assignStudentRole(userId);
            log.debug("成功为学生分配学生角色");
            
            log.info("成功创建学生账号：用户名={}, 昵称={}, 用户ID={}", username, studentData.getStudentName(), userId);
            return userId;
            
        } catch (Exception e) {
            log.error("创建学生账号失败，学生姓名: {}, 错误: {}", studentData.getStudentName(), e.getMessage(), e);
            throw new RuntimeException("创建学生账号失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public BatchCreationResult batchAutoCreate(List<NewExamScoreImportExcelVO> importDataList) {
        List<String> createdClasses = new ArrayList<>();
        List<String> createdStudents = new ArrayList<>();
        List<String> errorMessages = new ArrayList<>();
        List<String> warningMessages = new ArrayList<>();
        
        int createdClassCount = 0;
        int createdStudentCount = 0;
        int createdUserCount = 0;
        
        try {
            long startTime = System.currentTimeMillis();
            
            // 【性能优化1】：在批量创建开始时缓存部门ID和岗位ID，避免重复查询
            Long cachedDeptId = getStudentDeptId();
            Long cachedPostId = getStudentPostId();
            if (cachedDeptId == null || cachedPostId == null) {
                throw new RuntimeException("未找到学生部门或岗位，请先创建");
            }
            log.info("缓存部门ID和岗位ID完成：deptId={}, postId={}", cachedDeptId, cachedPostId);
            
            // 学生存在性检查已移至 batchCreateStudentsForClass 方法内部，以确保数据一致性和处理同名冲突，
            // 此处不再进行预查询，避免引入不一致的、不安全的匹配逻辑。
            
            // 按班级分组
            Map<String, List<NewExamScoreImportExcelVO>> dataByClass = importDataList.stream()
                .collect(Collectors.groupingBy(NewExamScoreImportExcelVO::getClassName));
            
            // 用于批量更新班级学生数
            Map<Long, Integer> classStudentCountMap = new HashMap<>();
            
            for (Map.Entry<String, List<NewExamScoreImportExcelVO>> entry : dataByClass.entrySet()) {
                String className = entry.getKey();
                List<NewExamScoreImportExcelVO> classStudents = entry.getValue();
                
                try {
                    log.info("开始创建班级: {}", className);
                    
                    // 检查班级是否已存在
                    ExamClassDO existingClass = checkClassExists(className);
                    if (existingClass == null) {
                        // 创建新班级
                        Long classId = autoCreateClassFromName(className);
                        existingClass = examClassMapper.selectById(classId);
                        if (existingClass != null) {
                            createdClasses.add(className);
                            createdClassCount++;
                        } else {
                            log.error("班级创建后无法查询到，班级名称: {}, 返回的班级ID: {}", className, classId);
                            errorMessages.add(String.format("班级创建异常：%s - 创建后无法查询到班级信息", className));
                            continue;
                        }
                    } else {
                        log.info("班级{}已存在，班级ID: {}", className, existingClass.getId());
                        if (!createdClasses.contains(className)) {
                            createdClasses.add(className);
                        }
                    }
                    
                    // 【性能优化3】：批量创建学生，而不是逐个创建
                    int newStudentsInClass = batchCreateStudentsForClass(
                        existingClass, classStudents, 
                        cachedDeptId, cachedPostId, 
                        createdStudents, errorMessages
                    );
                    
                    createdStudentCount += newStudentsInClass;
                    createdUserCount += newStudentsInClass;
                    
                    // 记录班级的学生数变化
                    classStudentCountMap.put(existingClass.getId(), newStudentsInClass);
                    
                } catch (Exception e) {
                    log.error("处理班级{}时发生错误: {}", className, e.getMessage(), e);
                    errorMessages.add(String.format("创建班级失败：%s - %s", className, e.getMessage()));
                }
            }
            
            // 【性能优化4】：批量更新班级学生数，而不是每个学生都更新一次
            batchUpdateClassStudentCounts(classStudentCountMap);
            
            long endTime = System.currentTimeMillis();
            log.info("批量创建完成，耗时{}ms，创建{}个班级，{}个学生", 
                endTime - startTime, createdClassCount, createdStudentCount);
            
        } catch (Exception e) {
            log.error("批量创建过程中发生错误", e);
            errorMessages.add("批量创建过程中发生错误：" + e.getMessage());
        }
        
        boolean success = errorMessages.isEmpty();
        return new BatchCreationResult(success, importDataList.size(), createdClassCount, 
            createdStudentCount, createdUserCount, createdClasses, createdStudents, 
            errorMessages, warningMessages);
    }
    
    /**
     * 批量为一个班级创建学生（性能优化版本）
     */
    private int batchCreateStudentsForClass(
            ExamClassDO examClass, 
            List<NewExamScoreImportExcelVO> classStudents,
            Long cachedDeptId,
            Long cachedPostId,
            List<String> createdStudents,
            List<String> errorMessages) {
        
        List<ExamClassStudentDO> studentsToInsert = new ArrayList<>();
        int createdCount = 0;
        
        for (NewExamScoreImportExcelVO studentData : classStudents) {
            try {
                studentData.setClassId(examClass.getId());
                ExamClassStudentDO existingStudent = checkStudentExists(studentData);
                
                if (existingStudent != null) {
                    log.debug("学生{}已存在，跳过创建", studentData.getStudentName());
                    continue;
                }
                
                // 创建用户账号（使用缓存的部门ID和岗位ID）
                Long userId = autoCreateStudentUserOptimized(studentData, examClass.getClassCode(), 
                    cachedDeptId, cachedPostId);
                
                // 生成学号
                int currentCount = examClassStudentMapper.countByClassId(examClass.getId());
                String studentNo = studentData.getStudentNo();
                if (studentNo == null || studentNo.isEmpty()) {
                    studentNo = generateStudentNo(examClass.getClassCode(), currentCount + studentsToInsert.size() + 1);
                }
                
                // 创建学生记录（先不插入数据库，收集起来批量插入）
                ExamClassStudentDO student = new ExamClassStudentDO();
                student.setClassId(examClass.getId());
                student.setStudentId(userId);
                student.setStudentNo(studentNo);
                student.setStudentName(studentData.getStudentName());
                student.setClassName(studentData.getClassName());
                student.setExamNo(studentData.getExamNo());
                student.setSubjectCombination(studentData.getSubjectCombination());
                student.setPhone(extractPhoneFromData(studentData));
                student.setEmail(extractEmailFromData(studentData));
                student.setJoinTime(LocalDateTime.now());
                student.setStatus(1);
                
                studentsToInsert.add(student);
                createdStudents.add(studentData.getStudentName());
                createdCount++;
                
            } catch (Exception e) {
                log.error("创建学生失败，学生姓名: {}, 班级: {}, 错误: {}", 
                    studentData.getStudentName(), examClass.getClassName(), e.getMessage(), e);
                errorMessages.add(String.format("创建学生失败：%s - %s", 
                    studentData.getStudentName(), e.getMessage()));
            }
        }
        
        // 批量插入学生记录
        if (!studentsToInsert.isEmpty()) {
            examClassStudentMapper.insertBatch(studentsToInsert);
            log.info("批量插入{}个学生到班级{}", studentsToInsert.size(), examClass.getClassName());
        }
        
        return createdCount;
    }
    
    /**
     * 优化版本的创建用户方法（使用缓存的部门ID和岗位ID）
     * 注意：同一个班级的同一个学生应该复用账号，不同班级的同名学生应该有不同的账号
     */
    private Long autoCreateStudentUserOptimized(
            NewExamScoreImportExcelVO studentData, 
            String classCode,
            Long cachedDeptId,
            Long cachedPostId) {
        try {
            // 生成基础用户名（基于姓名、部门ID和班级代码）
            String baseUsername = generateStudentUsername(studentData.getStudentName(), classCode, cachedDeptId);
            
            // 首先检查基础用户名是否已存在
            // 这样可以确保同一个部门、同一个班级的同一个学生不会创建多个账号
            AdminUserDO existingUser = adminUserMapper.selectByUsername(baseUsername);
            if (existingUser != null) {
                log.debug("学生用户{}已存在（同部门同班级同姓名），复用已有账号，用户ID: {}", baseUsername, existingUser.getId());
                return existingUser.getId();
            }
            
            // 调用 generateUniqueUsername 确保用户名的唯一性
            String username = generateUniqueUsername(baseUsername);
            
            // 创建用户请求对象（使用缓存的部门ID和岗位ID，避免重复查询）
            UserSaveReqVO createUserReq = new UserSaveReqVO();
            createUserReq.setUsername(username);
            createUserReq.setPassword(DEFAULT_PASSWORD);
            createUserReq.setNickname(studentData.getStudentName());
            createUserReq.setRemark("系统自动创建的学生账号，初始密码：88888888，请首次登录后修改密码");
            createUserReq.setDeptId(cachedDeptId); // 使用缓存的部门ID
            createUserReq.setPostIds(Collections.singleton(cachedPostId)); // 使用缓存的岗位ID
            createUserReq.setEmail(extractEmailFromData(studentData));
            createUserReq.setMobile(extractPhoneFromData(studentData));
            createUserReq.setSex(0);
            createUserReq.setAvatar("");
            createUserReq.setStatus(1);
            
            // 使用AdminUserService创建用户
            Long userId = adminUserService.createUser(createUserReq);
            
            // 自动分配学生角色
            assignStudentRole(userId);
            
            log.debug("成功创建学生账号：用户名={}, 昵称={}, 用户ID={}", username, studentData.getStudentName(), userId);
            return userId;
            
        } catch (Exception e) {
            log.error("创建学生账号失败，学生姓名: {}, 错误: {}", studentData.getStudentName(), e.getMessage(), e);
            throw new RuntimeException("创建学生账号失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 批量更新班级学生数（性能优化）
     */
    private void batchUpdateClassStudentCounts(Map<Long, Integer> classStudentCountMap) {
        if (classStudentCountMap.isEmpty()) {
            return;
        }
        
        log.info("开始批量更新{}个班级的学生数", classStudentCountMap.size());
        
        for (Map.Entry<Long, Integer> entry : classStudentCountMap.entrySet()) {
            Long classId = entry.getKey();
            Integer newStudentCount = entry.getValue();
            
            // 【修复】无论是否新增学生，都应该统计并更新班级的实际学生总数
            // 因为班级可能已存在且已有学生，即使本次没有新增，也需要更新正确的student_count
            try {
                // 获取当前班级学生数（从exam_class_student表统计）
                int currentCount = examClassStudentMapper.countByClassId(classId);
                
                // 更新班级学生数
                ExamClassDO examClass = examClassMapper.selectById(classId);
                if (examClass != null) {
                    int oldCount = examClass.getStudentCount() != null ? examClass.getStudentCount() : 0;
                    examClass.setStudentCount(currentCount);
                    examClassMapper.updateById(examClass);
                    log.info("更新班级[{}]学生计数: {} → {} (本次新增: {})", 
                            examClass.getClassName(), oldCount, currentCount, newStudentCount);
                } else {
                    log.warn("未找到班级ID={}", classId);
                }
            } catch (Exception e) {
                log.error("更新班级ID={}的学生计数失败: {}", classId, e.getMessage(), e);
            }
        }
        
        log.info("批量更新班级学生数完成");
    }

    @Override
    public ClassInfo parseClassInfo(String className) {
        if (className == null || className.trim().isEmpty()) {
            return new ClassInfo("", "", className, "未知班级");
        }
        
        Matcher matcher = CLASS_NAME_PATTERN.matcher(className.trim());
        if (matcher.find()) {
            String grade = matcher.group(1);
            String classNumber = matcher.group(3);
            String description = grade + "年级" + classNumber + "班";
            
            return new ClassInfo(grade, classNumber, className, description);
        }
        
        // 如果无法解析，尝试简单提取
        if (className.contains("高")) {
            return new ClassInfo("高中", "1", className, "高中班级");
        } else if (className.contains("初")) {
            return new ClassInfo("初中", "1", className, "初中班级");
        }
        
        return new ClassInfo("未知", "1", className, "未知年级班级");
    }

    @Override
    public String generateClassCode(String grade, String classNumber) {
        String gradeCode;
        switch (grade) {
            case "高一": gradeCode = "G1"; break;
            case "高二": gradeCode = "G2"; break;
            case "高三": gradeCode = "G3"; break;
            case "初一": gradeCode = "J1"; break;
            case "初二": gradeCode = "J2"; break;
            case "初三": gradeCode = "J3"; break;
            default: gradeCode = "GX"; break;
        }
        
        return gradeCode + "C" + String.format("%02d", Integer.parseInt(classNumber));
    }

    @Override
    public String generateStudentUsername(String studentName, String classCode, Long deptId) {
        String prefix = getInitials3(studentName);
        return prefix + generateRandom5();
    }

    @Override
    public String generateStudentNo(String classCode, Integer sequence) {
        // 【修复】加入部门ID前缀，确保考号在多部门场景下的唯一性
        Long deptId = SecurityFrameworkUtils.getLoginUserDeptId();
        String baseStudentNo;
        if (deptId != null) {
            // 格式：部门ID-班级代码-序号，例如：101-G31-001
            baseStudentNo = deptId + "-" + classCode + "-" + String.format("%03d", sequence);
        } else {
            // 兼容没有部门ID的情况（向后兼容）
            baseStudentNo = classCode + String.format("%03d", sequence);
        }

        // 【重要】增加时间戳和随机数后缀，确保高并发下的唯一性
        // 格式：基础学号-时间戳后8位+3位随机数
        // 使用 ThreadLocalRandom 以获得更好的多线程性能
        String uniqueSuffix = String.valueOf(System.currentTimeMillis()).substring(5) + 
                              String.format("%03d", ThreadLocalRandom.current().nextInt(1000));
        
        return baseStudentNo + "-" + uniqueSuffix;
    }

    @Override
    public ExamClassDO checkClassExists(String className) {
        // 获取当前用户的部门ID
        Long currentUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
        if (currentUserDeptId != null) {
            // 根据班级名称和部门ID查询，避免不同部门的同名班级冲突
            return examClassMapper.selectByClassNameAndDeptId(className, currentUserDeptId);
        }
        // 如果没有部门ID，则仅根据班级名称查询（兼容旧逻辑）
        return examClassMapper.selectByClassName(className);
    }

    @Override
    public ExamClassStudentDO checkStudentExists(String studentName, String className) {
        // 先查找班级（已考虑部门ID，避免不同部门的同名班级冲突）
        ExamClassDO examClass = checkClassExists(className);
        if (examClass == null) {
            // 班级不存在
            return null;
        }

        // 使用班级ID和学生姓名查询，确保在正确的班级中查找学生
        List<ExamClassStudentDO> students = examClassStudentMapper.selectListByStudentNameAndClassId(studentName, examClass.getId());
        if (students.isEmpty()) {
            return null;
        }
        if (students.size() > 1) {
            String errorMsg = String.format("数据校验失败：在班级 [%s] 中发现 %d 个同名学生 [%s]。请使用班级ID区分或修正数据源。",
                    className, students.size(), studentName);
            log.error(errorMsg);
            throw new IllegalStateException(errorMsg);
        }
        return students.get(0);
    }

    /**
     * 检查学生是否已存在（增强版）
     * 优先使用考号进行精确匹配，如果考号为空，则使用姓名+班级进行匹配，并处理同名冲突
     *
     * @param studentData 包含学生信息的导入VO
     * @return 存在的学生实体，如果不存在则返回null
     */
    private ExamClassStudentDO checkStudentExists(NewExamScoreImportExcelVO studentData) {
        if (studentData.getClassId() != null) {
            List<ExamClassStudentDO> students = examClassStudentMapper
                    .selectListByStudentNameAndClassId(studentData.getStudentName(), studentData.getClassId());
            if (students.isEmpty()) {
                return null;
            }
            if (students.size() > 1) {
                String errorMsg = String.format("数据校验失败：在班级ID [%s] 中发现 %d 个同名学生 [%s]。请修正数据源。",
                        String.valueOf(studentData.getClassId()), students.size(), studentData.getStudentName());
                log.error(errorMsg);
                throw new IllegalStateException(errorMsg);
            }
            return students.get(0);
        }

        if (StringUtil.isNotBlank(studentData.getExamNo())) {
            ExamClassStudentDO student = examClassStudentMapper.selectByExamNo(studentData.getExamNo());
            if (student != null) {
                return student;
            }
        }

        return checkStudentExists(studentData.getStudentName(), studentData.getClassName());
    }

    @Override
    public boolean checkUsernameExists(String username) {
        return adminUserMapper.selectByUsername(username) != null;
    }

    @Override
    public String generateUniqueUsername(String baseUsername) {
        if (baseUsername != null && baseUsername.matches("[a-z]{3}[a-z0-9]{5}")) {
            String prefix = baseUsername.substring(0, 3);
            String candidate = baseUsername;
            while (checkUsernameExists(candidate)) {
                candidate = prefix + generateRandom5();
            }
            return candidate;
        }
        String username = baseUsername;
        int counter = 1;
        while (checkUsernameExists(username)) {
            username = baseUsername + counter;
            counter++;
        }
        return username;
    }

    private String generateRandomUsername8() {
        char[] alphabet = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
        StringBuilder sb = new StringBuilder(8);
        for (int i = 0; i < 8; i++) {
            int idx = ThreadLocalRandom.current().nextInt(alphabet.length);
            sb.append(alphabet[idx]);
        }
        return sb.toString();
    }

    private String generateRandom5() {
        char[] alphabet = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
        StringBuilder sb = new StringBuilder(5);
        for (int i = 0; i < 5; i++) {
            int idx = ThreadLocalRandom.current().nextInt(alphabet.length);
            sb.append(alphabet[idx]);
        }
        return sb.toString();
    }

    private static final HanyuPinyinOutputFormat PINYIN_FORMAT = new HanyuPinyinOutputFormat();
    static {
        PINYIN_FORMAT.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        PINYIN_FORMAT.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        PINYIN_FORMAT.setVCharType(HanyuPinyinVCharType.WITH_V);
    }

    private String getInitials3(String name) {
        StringBuilder sb = new StringBuilder(3);
        if (name != null) {
            for (char c : name.toCharArray()) {
                if (sb.length() >= 3) break;
                try {
                    String[] arr = PinyinHelper.toHanyuPinyinStringArray(c, PINYIN_FORMAT);
                    if (arr != null && arr.length > 0) {
                        char ch = arr[0].charAt(0);
                        if (Character.isLetter(ch)) sb.append(Character.toLowerCase(ch));
                    } else if (Character.isLetter(c)) {
                        sb.append(Character.toLowerCase(c));
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    if (Character.isLetter(c)) sb.append(Character.toLowerCase(c));
                }
            }
        }
        while (sb.length() < 3) sb.append('x');
        return sb.toString();
    }

    @Override
    public CreationValidationResult validateCreationData(List<NewExamScoreImportExcelVO> importDataList) {
        List<String> errorMessages = new ArrayList<>();
        List<String> warningMessages = new ArrayList<>();
        List<String> invalidClassNames = new ArrayList<>();
        List<String> invalidStudentNames = new ArrayList<>();
        
        // 检查重复数据
        Set<String> classNames = new HashSet<>();
        Set<String> studentKeys = new HashSet<>();
        int duplicateClassCount = 0;
        int duplicateStudentCount = 0;
        
        for (NewExamScoreImportExcelVO data : importDataList) {
            // 验证班级名称
            if (data.getClassName() == null || data.getClassName().trim().isEmpty()) {
                errorMessages.add("班级名称不能为空");
                invalidClassNames.add("空班级名称");
            } else {
                ClassInfo classInfo = parseClassInfo(data.getClassName());
                if ("未知".equals(classInfo.getGrade())) {
                    warningMessages.add("无法解析班级名称：" + data.getClassName());
                    invalidClassNames.add(data.getClassName());
                }
                classNames.add(data.getClassName());
            }
            
            // 验证学生姓名
            if (data.getStudentName() == null || data.getStudentName().trim().isEmpty()) {
                errorMessages.add("学生姓名不能为空");
                invalidStudentNames.add("空学生姓名");
            } else {
                String studentKey = data.getClassName() + "_" + data.getStudentName();
                if (studentKeys.contains(studentKey)) {
                    duplicateStudentCount++;
                    warningMessages.add(String.format("发现重复学生：%s - %s", 
                        data.getClassName(), data.getStudentName()));
                }
                studentKeys.add(studentKey);
            }
            
            // 验证选科组合
            if (data.getSubjectCombination() == null || data.getSubjectCombination().trim().isEmpty()) {
                warningMessages.add(String.format("学生 %s 缺少选科组合信息", data.getStudentName()));
            }
        }
        
        boolean valid = errorMessages.isEmpty();
        return new CreationValidationResult(valid, errorMessages, warningMessages, 
            duplicateStudentCount, duplicateClassCount, invalidClassNames, invalidStudentNames);
    }

    /**
     * 获取当前操作用户ID
     * 
     * @return 当前用户ID
     */
    private Long getCurrentUserId() {
        return SecurityFrameworkUtils.getLoginUserId();
    }

    @Override
    public Long getDefaultTeacherId() {
        // 查找默认的班主任账号
        AdminUserDO defaultTeacher = adminUserMapper.selectByUsername("default_teacher");
        return defaultTeacher != null ? defaultTeacher.getId() : null;
    }

    @Override
    @Transactional
    public Long createDefaultTeacher(String className) {
        try {
            log.debug("开始为班级{}创建班主任账号", className);
            
            // 获取教师部门ID
            Long deptId = getTeacherDeptId();
            if (deptId == null) {
                throw new RuntimeException("未找到教师部门，请先创建名为'教师部'的部门");
            }
            
            // 生成基于班级名称和部门ID的用户名
            String baseUsername = generateTeacherUsername(className, deptId);
            log.debug("生成基础班主任用户名: {}", baseUsername);
            
            // 检查基础用户名是否已存在
            // 同一个部门的同一个班级的班主任应该复用同一个账号
            AdminUserDO existingUser = adminUserMapper.selectByUsername(baseUsername);
            if (existingUser != null) {
                log.info("班主任用户{}已存在（同部门同班级），复用已有账号，用户ID: {}", baseUsername, existingUser.getId());
                return existingUser.getId();
            }
            
            // 如果基础用户名不存在，直接使用它
            String username = baseUsername;
            log.debug("使用班主任用户名: {}", username);
            
            // 获取教师岗位ID
            Long postId = getTeacherPostId();
            if (postId == null) {
                throw new RuntimeException("未找到教师岗位，请先创建名为'教师'的岗位");
            }
            
            // 创建用户请求对象
            UserSaveReqVO createUserReq = new UserSaveReqVO();
            createUserReq.setUsername(username);
            createUserReq.setPassword(DEFAULT_PASSWORD); // 会自动加密
            createUserReq.setNickname(className + "班主任");
            createUserReq.setRemark("系统自动创建的" + className + "班主任账号，初始密码：88888888，请首次登录后修改密码");
            createUserReq.setDeptId(deptId); // 教师部门
            createUserReq.setPostIds(Collections.singleton(postId)); // 教师岗位
            createUserReq.setEmail("");
            createUserReq.setMobile("");
            createUserReq.setSex(0); // 未知性别
            createUserReq.setAvatar("");
            createUserReq.setStatus(1); // 启用状态
            
            // 使用AdminUserService创建用户，会自动加密密码
            Long userId = adminUserService.createUser(createUserReq);
            log.debug("成功创建班主任用户，用户ID: {}", userId);
            
            // 自动分配教师角色
            assignTeacherRole(userId);
            log.debug("成功为班主任分配教师角色");
            
            log.info("成功创建班主任账号：用户名={}, 昵称={}, 用户ID={}", username, className + "班主任", userId);
            return userId;
            
        } catch (Exception e) {
            log.error("创建班主任账号失败，班级: {}, 错误: {}", className, e.getMessage(), e);
            throw new RuntimeException("创建班主任账号失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取教师部门ID
     */
    private Long getTeacherDeptId() {
        try {
            // 通过部门名称查找教师部门
            List<DeptDO> depts = deptMapper.selectList(new LambdaQueryWrapperX<DeptDO>()
                    .eq(DeptDO::getName, "教师部")
                    .eq(DeptDO::getStatus, 0)
                    .eq(DeptDO::getDeleted, false));
            
            if (!depts.isEmpty()) {
                log.info("找到教师部门: 教师部, ID: {}", depts.get(0).getId());
                return depts.get(0).getId();
            }
            
            // 如果没有找到，尝试查找其他可能的教师部门名称
            String[] teacherDeptNames = {"教师部", "教师", "教学部", "师资部"};
            for (String deptName : teacherDeptNames) {
                depts = deptMapper.selectList(new LambdaQueryWrapperX<DeptDO>()
                        .eq(DeptDO::getName, deptName)
                        .eq(DeptDO::getStatus, 0)
                        .eq(DeptDO::getDeleted, false));
                if (!depts.isEmpty()) {
                    log.info("找到教师部门: {}, ID: {}", deptName, depts.get(0).getId());
                    return depts.get(0).getId();
                }
            }
            
            log.warn("未找到教师部门，请确保已创建名为'教师部'的部门");
            return null;
            
        } catch (Exception e) {
            log.error("查找教师部门时发生错误: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 获取教师岗位ID
     */
    private Long getTeacherPostId() {
        try {
            // 通过岗位名称查找教师岗位
            PostDO post = postMapper.selectByName("教师");
            
            if (post != null && post.getStatus() == 0 && !post.getDeleted()) {
                log.info("找到教师岗位: 教师, ID: {}", post.getId());
                return post.getId();
            }
            
            // 如果没有找到，尝试查找其他可能的教师岗位名称
            String[] teacherPostNames = {"教师", "班主任", "任课教师", "教学岗"};
            for (String postName : teacherPostNames) {
                post = postMapper.selectByName(postName);
                if (post != null && post.getStatus() == 0 && !post.getDeleted()) {
                    log.info("找到教师岗位: {}, ID: {}", postName, post.getId());
                    return post.getId();
                }
            }
            
            log.warn("未找到教师岗位，请确保已创建名为'教师'的岗位");
            return null;
            
        } catch (Exception e) {
            log.error("查找教师岗位时发生错误: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 获取学生部门ID
     */
    private Long getStudentDeptId() {
        try {
            // 通过部门名称查找学生部门
            List<DeptDO> depts = deptMapper.selectList(new LambdaQueryWrapperX<DeptDO>()
                    .eq(DeptDO::getName, "学生部")
                    .eq(DeptDO::getStatus, 0)
                    .eq(DeptDO::getDeleted, false));
            
            if (!depts.isEmpty()) {
                log.info("找到学生部门: 学生部, ID: {}", depts.get(0).getId());
                return depts.get(0).getId();
            }
            
            // 如果没有找到，尝试查找其他可能的学生部门名称
            String[] studentDeptNames = {"学生部", "学生", "学生处", "学工部"};
            for (String deptName : studentDeptNames) {
                depts = deptMapper.selectList(new LambdaQueryWrapperX<DeptDO>()
                        .eq(DeptDO::getName, deptName)
                        .eq(DeptDO::getStatus, 0)
                        .eq(DeptDO::getDeleted, false));
                if (!depts.isEmpty()) {
                    log.info("找到学生部门: {}, ID: {}", deptName, depts.get(0).getId());
                    return depts.get(0).getId();
                }
            }
            
            log.warn("未找到学生部门，请确保已创建名为'学生部'的部门");
            return null;
            
        } catch (Exception e) {
            log.error("查找学生部门时发生错误: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 获取学生岗位ID
     */
    private Long getStudentPostId() {
        try {
            // 通过岗位名称查找学生岗位
            PostDO post = postMapper.selectByName("学生");
            
            if (post != null && post.getStatus() == 0 && !post.getDeleted()) {
                log.info("找到学生岗位: 学生, ID: {}", post.getId());
                return post.getId();
            }
            
            // 如果没有找到，尝试查找其他可能的学生岗位名称
            String[] studentPostNames = {"学生", "在校学生", "学员", "学生岗"};
            for (String postName : studentPostNames) {
                post = postMapper.selectByName(postName);
                if (post != null && post.getStatus() == 0 && !post.getDeleted()) {
                    log.info("找到学生岗位: {}, ID: {}", postName, post.getId());
                    return post.getId();
                }
            }
            
            log.warn("未找到学生岗位，请确保已创建名为'学生'的岗位");
            return null;
            
        } catch (Exception e) {
            log.error("查找学生岗位时发生错误: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 从导入数据中提取手机号
     */
    private String extractPhoneFromData(NewExamScoreImportExcelVO studentData) {
        // 这里可以根据实际需要从studentData中提取手机号
        // 目前返回空字符串
        return "";
    }
    
    /**
     * 从导入数据中提取邮箱
     */
    private String extractEmailFromData(NewExamScoreImportExcelVO studentData) {
        // 这里可以根据实际需要从studentData中提取邮箱
        // 目前返回空字符串
        return "";
    }
    
    /**
     * 生成班主任用户名
     * 【简化格式】基于班级名称和部门ID生成简短易记的用户名
     * 例如：高二4班 → t122g2c4 (teacher缩写 + 部门ID + 年级 + 班号)
     * 
     * @param className 班级名称
     * @param deptId 部门ID（用于区分不同学校/部门）
     * @return 用户名
     */
    private String generateTeacherUsername(String className, Long deptId) {
        String username;
        try {
            // 提取年级和班号信息
            String gradeInfo = extractGradeInfo(className);  // 如：高二 → g2, 初三 → c3
            String classNum = extractClassNumber(className);  // 如：4班 → c4
            
            String deptSuffix = deptId != null ? String.valueOf(deptId) : "";
            
            if (StringUtil.isNotBlank(gradeInfo) && StringUtil.isNotBlank(classNum)) {
                // 格式：t + 部门ID + 年级 + 班号 (例如：t122g2c4)
                username = "t" + deptSuffix + gradeInfo + classNum;
            } else {
                // 如果无法提取，使用完整拼音（简化版）
                String pinyin = PinyinUtils.convertToPinyin(className);
                if (StringUtil.isNotBlank(pinyin)) {
                    // 限制拼音长度
                    String shortPinyin = pinyin.length() > 10 ? pinyin.substring(0, 10) : pinyin;
                    username = "t" + deptSuffix + shortPinyin.toLowerCase();
                } else {
                    // 如果转换失败，使用时间戳
                    username = "teacher" + System.currentTimeMillis();
                }
            }
        } catch (Exception e) {
            log.warn("生成班主任用户名失败，班级: {}", className, e);
            username = "teacher" + System.currentTimeMillis();
        }
        
        return username;
    }
    
    /**
     * 从班级名称中提取年级信息
     * @param className 班级名称，如"高二4班"、"初三1班"
     * @return 年级简码，如"g2"（高二）、"c3"（初三）、"g1"（高一）
     */
    private String extractGradeInfo(String className) {
        if (className == null) return "";
        
        // 高中年级
        if (className.contains("高一") || className.contains("高1")) return "g1";
        if (className.contains("高二") || className.contains("高2")) return "g2";
        if (className.contains("高三") || className.contains("高3")) return "g3";
        
        // 初中年级
        if (className.contains("初一") || className.contains("初1") || className.contains("七年级")) return "c1";
        if (className.contains("初二") || className.contains("初2") || className.contains("八年级")) return "c2";
        if (className.contains("初三") || className.contains("初3") || className.contains("九年级")) return "c3";
        
        return "";
    }
    
    /**
     * 从班级名称中提取班号
     * @param className 班级名称，如"高二4班"、"高二(4)班"
     * @return 班号简码，如"c4"（4班）
     */
    private String extractClassNumber(String className) {
        if (className == null) return "";
        
        // 尝试匹配各种格式的班号
        // 格式1: X班 (如"4班")
        java.util.regex.Pattern pattern1 = java.util.regex.Pattern.compile("(\\d+)班");
        java.util.regex.Matcher matcher1 = pattern1.matcher(className);
        if (matcher1.find()) {
            return "c" + matcher1.group(1);
        }
        
        // 格式2: (X)班 (如"(4)班")
        java.util.regex.Pattern pattern2 = java.util.regex.Pattern.compile("\\((\\d+)\\)班");
        java.util.regex.Matcher matcher2 = pattern2.matcher(className);
        if (matcher2.find()) {
            return "c" + matcher2.group(1);
        }
        
        // 格式3: 年级X班 (如"年级4班")
        java.util.regex.Pattern pattern3 = java.util.regex.Pattern.compile("级(\\d+)班");
        java.util.regex.Matcher matcher3 = pattern3.matcher(className);
        if (matcher3.find()) {
            return "c" + matcher3.group(1);
        }
        
        return "";
    }
    
    /**
     * 为用户分配教师角色
     * 
     * @param userId 用户ID
     */
    private void assignTeacherRole(Long userId) {
        try {
            // 查找教师角色
            List<RoleDO> roles = roleService.getRoleList();
            RoleDO teacherRole = roles.stream()
                .filter(role -> RoleCodeEnum.TEACHER.getCode().equals(role.getCode()))
                .findFirst()
                .orElse(null);
            
            if (teacherRole != null) {
                // 分配教师角色
                permissionService.assignUserRole(userId, Collections.singleton(teacherRole.getId()));
                log.info("成功为用户ID={}分配教师角色", userId);
            } else {
                log.warn("未找到教师角色，请先在系统中创建code为'teacher'的角色");
            }
        } catch (Exception e) {
            log.error("为用户ID={}分配教师角色失败", userId, e);
        }
    }
    
    /**
     * 为用户分配学生角色
     * 
     * @param userId 用户ID
     */
    private void assignStudentRole(Long userId) {
        try {
            // 查找学生角色
            List<RoleDO> roles = roleService.getRoleList();
            RoleDO studentRole = roles.stream()
                .filter(role -> RoleCodeEnum.STUDENT.getCode().equals(role.getCode()))
                .findFirst()
                .orElse(null);
            
            if (studentRole != null) {
                // 分配学生角色
                permissionService.assignUserRole(userId, Collections.singleton(studentRole.getId()));
                log.info("成功为用户ID={}分配学生角色", userId);
            } else {
                log.warn("未找到学生角色，请先在系统中创建code为'student'的角色");
            }
        } catch (Exception e) {
            log.error("为用户ID={}分配学生角色失败", userId, e);
        }
    }
}